package cn.wygandwdn.core.transport.client;

import cn.wygandwdn.common.message.RpcRequest;
import cn.wygandwdn.core.config.Config;
import cn.wygandwdn.core.registry.ServiceDiscovery;
import cn.wygandwdn.core.transport.client.handler.RpcClientResponseHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;

/**
 * @description:
 * @author: WYG
 * @time: 2021/10/27 16:04
 */

public class RpcClient {

    private static final Logger log = LoggerFactory.getLogger(RpcClient.class);

    private final ServiceDiscovery discovery;

    public RpcClient() {
        this.discovery = Config.getDiscovery();
    }

    public Promise<Object> sendRequest(RpcRequest request) {
        if (discovery == null) {
            log.error("未设置负载均衡策略");
        }
        // 负载均衡,服务发现
        InetSocketAddress address = discovery.lookupService(request.getServiceName());
        if (address == null) {
            log.error("请求的服务不存在,请检查group和version,确认是否与服务端一致");
        }
        Channel channel = RpcChannel.get(address);
        // 发送请求
        channel.writeAndFlush(request).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                log.debug("客户端发送消息: {}", request);
            } else {
                log.error("发送消息时发生错误: {}", future.cause());
                future.channel().close();
            }
        });
        /*
         promise对象接收响应结果
         使用EventLoop对象是为了使用该线程异步执行promise的任务,例如
            promise.addListener(future -> {
            });
         */

        // 检查是否存在请求对应的promise,如果存在则直接复用旧的promise
        if (RpcClientResponseHandler.PROMISE.containsKey(request.getSequenceId())) {
            return RpcClientResponseHandler.PROMISE.get(request.getSequenceId());
        }
        DefaultPromise<Object> promise = new DefaultPromise<>(channel.eventLoop());
        RpcClientResponseHandler.PROMISE.put(request.getSequenceId(), promise);
        return promise;
    }

}
